package com.example.pengxiangedupay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.pengxiangedupay.dao.FeeStuPaidDao;
import com.example.pengxiangedupay.dto.FeeDetailDto;
import com.example.pengxiangedupay.dto.FeeItemDto;
import com.example.pengxiangedupay.entity.FeeStuNeedPayEntity;
import com.example.pengxiangedupay.entity.FeeStuPaidEntity;
import com.example.pengxiangedupay.entity.FeeTypeEntity;
import com.example.pengxiangedupay.entity.StuBaseInfoEntity;
import com.example.pengxiangedupay.service.FeeStuNeedPayService;
import com.example.pengxiangedupay.service.FeeStuPaidService;
import com.example.pengxiangedupay.service.FeeTypeService;
import com.example.pengxiangedupay.service.StuBaseInfoService;
import com.example.pengxiangedupay.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class FeeStuPaidServiceImpl extends ServiceImpl<FeeStuPaidDao,FeeStuPaidEntity> implements FeeStuPaidService {

    @Autowired
    FeeTypeService feeTypeService;
    @Autowired
    FeeStuNeedPayService feeStuNeedPayService;

    @Autowired
    StuBaseInfoService stuBaseInfoService;
    @Override
    public List<FeeItemVo> getFeePaidInfo(Long studentId) {
//        String type = getDeptByStuId(studentId)
        String reduce = getReduceInfoById(studentId);
        List<FeeItemDto> feeItemDtos = this.baseMapper.getFeePaidInfo(studentId);
        List<FeeItemVo> feeItemVoList = feeItemDtos.stream().map(item -> {
            FeeItemVo feeItemVo = new FeeItemVo();
            feeItemVo.setTotal(item.getTotalNeedFee().toString());
            feeItemVo.setFeeId(item.getId());
            feeItemVo.setStatus(item.getFeeStatus());
            //拼接费用类型字符串
//            String type = item.getDeptDescription() + '(' + item.getSchoolYearInfo() + ')';
            feeItemVo.setType(item.getBillInfo());
            feeItemVo.setBreakType(reduce);
            return feeItemVo;
        }).collect(Collectors.toList());
        return feeItemVoList;
    }

    @Override
    public List<FeeItemVo> getFeeNotPayInfo(Long studentId) {
//        String type = getDeptByStuId(studentId);
        String reduce = getReduceInfoById(studentId);
        List<FeeItemDto> feeItemDtos = this.baseMapper.getFeeNotPayInfo(studentId);
        List<FeeItemVo> feeItemVoList = feeItemDtos.stream().map(item -> {
            FeeItemVo feeItemVo = new FeeItemVo();
            feeItemVo.setTotal(item.getTotalNeedFee().toString());
            feeItemVo.setFeeId(item.getId());
            feeItemVo.setStatus(item.getFeeStatus());
            //拼接费用类型字符串
//            String type = item.getDeptDescription() + '(' + item.getSchoolYearInfo() + ')';
            feeItemVo.setType(item.getBillInfo());
            feeItemVo.setBreakType(reduce);
            return feeItemVo;
        }).collect(Collectors.toList());
        return feeItemVoList;
    }

    @Override
    public FeeItemDetailVo getFeeDetail(Long feeId) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        if(feeId == null){
            return null;
        }
        //查询所有的缴费种类
        Map<String, String> typeMap = feeTypeService.list().stream().collect(Collectors.toMap(FeeTypeEntity::getType, FeeTypeEntity::getDescription));

        FeeDetailDto feeDetailDto = this.baseMapper.getFeeDetailDto(feeId);
        System.out.println(feeDetailDto);
        Long stuId = feeDetailDto.getStuId();
//        String type = getDeptByStuId(stuId);
        FeeStuPaidEntity feeStuPaid = this.getById(feeId);
        String reduce = getReduceInfoById(stuId);
        //封装前端需要的对象
        FeeItemDetailVo feeItemDetailVo = new FeeItemDetailVo();
        feeItemDetailVo.setFeeStatus(feeDetailDto.getFeeStatus());
        //拼接费用类型字符串
//        String type = feeDetailDto.getDeptDescription() + '(' + feeDetailDto.getSchoolYearInfo() + ')';
        feeItemDetailVo.setFeeType(feeStuPaid.getBillInfo());
        //拼接减免类型字符串(枚举)这块有疑问 暂时写死
        feeItemDetailVo.setBreakType(reduce);
        //
        List<FeeDetailVo> list = new ArrayList<>();
        //添加应缴纳费用明细
        //训练费
        FeeDetailVo trainFeeDetail = getFeeDetailVoByName("Train", feeDetailDto,typeMap);
        FeeDetailVo clothesFeeDetail = getFeeDetailVoByName("Clothes", feeDetailDto,typeMap);
        FeeDetailVo bookFeeDetail = getFeeDetailVoByName("Book", feeDetailDto,typeMap);
        FeeDetailVo hotelFeeDetail = getFeeDetailVoByName("Hotel", feeDetailDto,typeMap);
        FeeDetailVo bedFeeDetail = getFeeDetailVoByName("Bed", feeDetailDto,typeMap);
        FeeDetailVo insuranceFeeDetail = getFeeDetailVoByName("Insurance", feeDetailDto,typeMap);
        FeeDetailVo publicFeeDetail = getFeeDetailVoByName("Public", feeDetailDto,typeMap);
        FeeDetailVo certificateFeeDetail = getFeeDetailVoByName("Certificate", feeDetailDto,typeMap);
        FeeDetailVo defenseEduFeeDetail = getFeeDetailVoByName("DefenseEdu", feeDetailDto,typeMap);
        FeeDetailVo bodyExamFeeDetail = getFeeDetailVoByName("BodyExam", feeDetailDto,typeMap);

        list.add(trainFeeDetail);
        list.add(clothesFeeDetail);
        list.add(bookFeeDetail);
        list.add(hotelFeeDetail);
        list.add(bedFeeDetail);
        list.add(insuranceFeeDetail);
        list.add(publicFeeDetail);
        list.add(certificateFeeDetail);
        list.add(defenseEduFeeDetail);
        list.add(bodyExamFeeDetail);
        //最后添加一条合计
        FeeDetailVo total = new FeeDetailVo();
        BigDecimal totalOrigin = new BigDecimal(0);
        BigDecimal totalNeed = new BigDecimal(0);
        BigDecimal totalPaid = new BigDecimal(0);
        for (FeeDetailVo feeDetailVo : list) {
            totalOrigin = totalOrigin.add(feeDetailVo.getOrigin());
            totalNeed = totalNeed.add(feeDetailVo.getNeed());
            totalPaid = totalPaid.add(feeDetailVo.getPaid());
        }
        total.setOrigin(totalOrigin);
        total.setPaid(totalPaid);
        total.setNeed(totalNeed);
        total.setBreakFee(totalOrigin.subtract(totalNeed));
        total.setLeft(totalNeed.subtract(totalPaid));
        total.setType("费用合计");
        list.add(total);
        feeItemDetailVo.setFeeDetailVoList(list);
        //这边设置  还需要缴纳费用总和
        feeItemDetailVo.setTotal(new BigDecimal(14000));
        return feeItemDetailVo;
    }

    @Override
    @Transactional
    public boolean updatePay(Long feeId, JSONObject feePayJson){
        FeeStuPaidEntity updateEntity = new FeeStuPaidEntity();
        //查询feeId对应的支付项
        FeeStuPaidEntity feeStuPaidEntity = baseMapper.selectById(feeId);
        //判断是否是新生,是新生 入学状态 100 -》200
        Long stuId = feeStuPaidEntity.getStuId();
        StuBaseInfoEntity stuBaseInfoEntity = stuBaseInfoService.getById(stuId);
        if(stuBaseInfoEntity.getEntranceStatus() == 100){
            stuBaseInfoEntity.setEntranceStatus(200);
        }
        //不存在 或者已经是支付完成状态
        if(feeStuPaidEntity == null || feeStuPaidEntity.getFeeStatus()==800){
            return false;
        }
        //更新数据库
        //支付状态
        //计算还剩多少没缴
        Long needPayId = feeStuPaidEntity.getFeeNeedPayId();
        FeeStuNeedPayEntity feeStuNeedPayEntity = feeStuNeedPayService.getById(needPayId);
        BeanUtils.copyProperties(feeStuPaidEntity,updateEntity);
        BigDecimal totalNeedFee = feeStuNeedPayEntity.getTotalNeedFee();
        Map<String, String> typeMap = feeTypeService.list().stream().collect(Collectors.toMap(FeeTypeEntity::getDescription, FeeTypeEntity::getType));
        //更新缴费部分
        feePayJson.forEach((key,value)->{
            //排除掉费用合计这一项
            if("费用合计".equals(key)){
                return;
            }
            //key：例 培训费
            BigDecimal money = new BigDecimal(value+"");
            String name = typeMap.get(key);
            try {
                String methodNameGet = "get" + name + "Fee";
                Method feeMethodGet = feeStuPaidEntity.getClass().getMethod(methodNameGet);
                BigDecimal OriginMoney = (BigDecimal) feeMethodGet.invoke(feeStuPaidEntity);
                BigDecimal newMoney = OriginMoney.add(money);
                String methodName = "set" + name + "Fee";
                Method feeMethod = updateEntity.getClass().getMethod(methodName,BigDecimal.class);
                feeMethod.invoke(updateEntity,newMoney);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        });
        BigDecimal originPaid = feeStuPaidEntity.getTotalPaidFee();
        BigDecimal resultPaid = originPaid.add(new BigDecimal(feePayJson.get("费用合计")+""));
        updateEntity.setTotalPaidFee(resultPaid);
        if(totalNeedFee.compareTo(resultPaid) == 0){
            updateEntity.setFeeStatus(800);
            stuBaseInfoEntity.setFeeStatus(800);
        }
        this.baseMapper.updateById(updateEntity);
        stuBaseInfoService.updateById(stuBaseInfoEntity);
        return true;
    }

    //方法作用为通过名字得到对应的FeeDetailVo，由于数据库设计原因，有大量重复代码，考虑使用反射抽取重复代码。
    public FeeDetailVo getFeeDetailVoByName(String name,FeeDetailDto feeDetailDto,Map<String, String> typeMap) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//        Class clazz = FeeDetailVo.class;
//        String className = name + "FeeDetail";
        //例如此时name = Train
        FeeDetailVo feeDetailVo = new FeeDetailVo();
        //传入值为
        //获取feePaid
        String methodNamePaid = "get" + name + "FeePaid";
        Method getFeePaidMethod = feeDetailDto.getClass().getMethod(methodNamePaid,null);
        BigDecimal feePaid = (BigDecimal) getFeePaidMethod.invoke(feeDetailDto);
        //获取feeNeed
        String methodNameNeed = "get" + name + "FeeNeed";
        Method getFeeNeedMethod = feeDetailDto.getClass().getMethod(methodNameNeed,null);
        BigDecimal feeNeed = (BigDecimal) getFeeNeedMethod.invoke(feeDetailDto);
        //获取feeOrigin
        String methodNameOrigin = "get" + name + "FeeOrigin";
        Method getFeeOriginMethod = feeDetailDto.getClass().getMethod(methodNameOrigin,null);
        BigDecimal feeOrigin = (BigDecimal) getFeeOriginMethod.invoke(feeDetailDto);

        feeDetailVo.setBreakFee(feeOrigin.subtract(feeNeed));
        feeDetailVo.setPaid(feePaid);
        //获取name对应的中文
        String description = typeMap.getOrDefault(name,"");
        feeDetailVo.setType(description);
        feeDetailVo.setNeed(feeNeed);
        feeDetailVo.setLeft(feeNeed.subtract(feePaid));
        feeDetailVo.setOrigin(feeOrigin);

        return feeDetailVo;
    }

    public String getDeptByStuId(Long studentId){
        DeptDescriptionVo deptDescription = stuBaseInfoService.getDeptById(studentId);
        String type = deptDescription.getGradeName() +deptDescription.getMajorName() + deptDescription.getClassName();
        type += deptDescription.getClassType() == 0?"(升学)":"(就业)";
        return type;
    }
    public String getReduceInfoById(Long studentId){
        ReduceInfo reduceInfo = stuBaseInfoService.getReduceById(studentId);
        String reduce = "助学金减免:"+ reduceInfo.getReduceEcoType() +";  贫困减免:" + reduceInfo.getReduceStipendType();
        return reduce;
    }

}
